import path from "path";
import fs from "fs";
import { defineConfig, Plugin } from "vite";
import react from "@vitejs/plugin-react";
import svgr from "vite-plugin-svgr";

const isStandalone = /true/.test(process.env.STANDALONE || "");

console.log({ isStandalone });

export default defineConfig({
  build: {
    rollupOptions: {
      ...(isStandalone && {
        output: {
          format: "iife",
          entryFileNames(chunkInfo) {
            return "assets/index-Bq5QuuBh.js";
          },
        },
      }),
    },
  },
  define: {
    __STANDALONE__: isStandalone,
  },
  plugins: [
    react(),
    svgr({
      include: "**/*.svg?jsx",
      svgrOptions: {
        svgoConfig: {
          plugins: [
            {
              name: "preset-default",
              params: {
                overrides: {
                  // viewBox is required to resize SVGs with CSS.
                  // @see https://github.com/svg/svgo/issues/1128
                  removeViewBox: false,
                },
              },
            },
          ],
        },
      },
    }),
    ...(isStandalone
      ? [imgToDataUrl(), cssPrefix({ prefix: ".group\\/yh-qa", debug: true })]
      : []),
  ],
  resolve: {
    alias: {
      "@": path.resolve(process.cwd(), "src"),
    },
  },
  server: {
    proxy: {
      // if backend available
      "/zs": "http://192.168.0.108:8025",
      // otherwise `node mock-server.js`
      // "/zs": "http://localhost:9999",
    },
  },
});

function imgToDataUrl(): Plugin {
  return {
    name: "image-to-data-url",
    async transform(code, id) {
      if (/\.png$/.test(id)) {
        return new Promise((resolve, reject) => {
          fs.readFile(id, { encoding: "base64" }, (err, data) => {
            if (err) {
              return reject(err);
            }
            resolve({ code: `export default "data:image/png;base64,${data}"` });
          });
        });
      }
    },
    generateBundle(options, bundle) {
      for (const key in bundle) {
        if (
          bundle[key].type === "asset" &&
          /\.png$/.test(bundle[key].fileName)
        ) {
          delete bundle[key];
        }
      }
    },
  };
}

/**
 * 为 tailwindcss 生成的 css 样式添加作用域
 */
function cssPrefix({
  prefix,
  debug,
}: {
  prefix: string;
  debug?: boolean;
}): Plugin {
  class State {
    static COMMENT = "c";
    static MEDIA_QUERY = "m";
    static CONTENT = "ct";
    blockStack: string[] = [];
    get top() {
      return this.blockStack[this.blockStack.length - 1];
    }
    pop() {
      this.blockStack.pop();
    }
    push(s: string) {
      this.blockStack.push(s);
    }
    parse(code: string) {
      const len = code.length;
      let did = false;
      let newCode = "";
      for (let i = 0; i < len; i++) {
        const prev = i > 0 ? code[i - 1] : "";
        const curr = code[i];
        const next = i < len ? code[i + 1] : "";
        // comment open
        if (curr === "/" && next === "*" && this.top !== State.COMMENT) {
          newCode += "/*";
          this.push(State.COMMENT);
          i += 1;
          continue;
        }
        // comment close
        if (curr === "*" && next === "/" && this.top === State.COMMENT) {
          newCode += "*/";
          this.pop();
          i += 1;
          continue;
        }

        if (this.top === State.COMMENT) {
          newCode += curr;
          continue;
        }

        if (curr === "{") {
          newCode += curr;
          this.push(State.CONTENT);
          did = false;
          continue;
        }
        if (curr === "}") {
          newCode += curr;
          this.pop();
          continue;
        }

        if (this.top === State.CONTENT) {
          newCode += curr;
          continue;
        }

        // block open
        if (curr === "@") {
          let blockType = "";
          let j = i;
          while (code[j]) {
            newCode += code[j];
            if (code[j] !== " ") {
              blockType += code[j];
            }
            if (code[j] === "{") {
              this.push(blockType);
              break;
            }
            if (code[j] === ";") {
              break;
            }
            j++;
          }
          i = j + 1;
          continue;
        }

        if (!/\n|\s/.test(curr) && !did) {
          did = true;
          newCode += prefix + " ";
        }

        if (curr === ",") {
          did = false;
        }

        newCode += curr;
      }
      return newCode;
    }
  }
  return {
    name: "css-prefix",
    transform(code, id, options) {
      if (!/tailwind\.css$/.test(id)) {
        return;
      }
      const s = new State();
      const newCode = s.parse(code);
      if (debug) {
        fs.writeFile(
          "tailwind.debug.css",
          `/* Build Time: ${new Date().toString()} */\n` + newCode,
          (err) => {},
        );
      }
      return newCode;
    },
  };
}
